package spoon.bet365.service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import spoon.bet365.domain.Game;
import spoon.bet365.domain.League;
import spoon.common.exception.ConvertException;
import spoon.domain.Betting;

@Service
@Qualifier("bet365FootballService")
public class Bet365FootballService extends Bet365ServiceImpl {

	@Value("${bet365.football.url}")
	private String connectionUrl;

	@Value("${bet365.football.item}")
	private String item;

	@Value("${bet365.football.name}")
	private String itemName;

	/**
	 * 축구는 United Kingdom 이후의 모든 PA 항목이 리그다.
	 */
	@Override
	public List<League> getLeague() {

		log.info("===================================================================");
		log.info("    Bet365 {} 리그 정보 검색 시작", itemName);

		List<League> leagueList = new ArrayList<League>();
		boolean isValid = false;
		String national = null;
		int leagueCnt = 0;

		String source = httpService.getSource(connectionUrl);
		StringTokenizer line = new StringTokenizer(source, "|");

		while (line.hasMoreElements()) {
			String token = line.nextToken();

			if (token.startsWith("MA")) {
				national = getTokenName(token, "NA");
				// 영국부터 시작한다.
				if ("United Kingdom".equals(national)) {
					isValid = true;
				}
			}

			if (isValid && token.startsWith("PA")) {
				League league = new League();
				league.setItem(item);
				league.setItemName(itemName);
				league.setNational(national);
				league.setGameId(getTokenName(token, "ID"));
				league.setLeague(getTokenName(token, "NA"));
				league.setLink(getTokenName(token, "PD"));
				leagueList.add(league);
				leagueCnt++;
			}
		}

		log.info("    Bet365 {} 리그 정보 검색 종료. 전체 추가 리그수 = {}", itemName, leagueCnt);
		log.info("===================================================================");

		return leagueList;
	}

	/**
	 * 리그별 경기
	 */
	@Override
	@Async
	public void getGame(League league) {

		long startTime = System.currentTimeMillis();

		int gameCnt = 0;
		int bettingCnt = 0;

		String url = getGameLink(league.getLink());
		league.setLink(url);

		// 리그별 게임 가져오기
		this.getGameList(league);

		// 데이터 입력
		bettingCnt = addBetting(league);
		gameCnt = league.getGameList().size();

		log.info("   사이트: {}, 종목: {}, 국가: {}, 리그: {}, 경기수: {}, 베팅수: {}, 소요시간: {}초", league.getSite(), league.getItem(), league.getNational(),
				league.getLeague(), gameCnt, bettingCnt, (System.currentTimeMillis() - startTime) / 1000.0f);
	}

	/**
	 * 리그별 게임 가져오기
	 * 
	 * @param league
	 * @return
	 */
	@Override
	protected void getGameList(League league) {
		Game game;

		// 경기시간, 팀영, 승, 무, 패배당, 링크 구분자
		int order = 0;

		List<String> dateList = new ArrayList<String>();
		List<String> teamList = new ArrayList<String>();
		List<String> homeList = new ArrayList<String>();
		List<String> drawList = new ArrayList<String>();
		List<String> awayList = new ArrayList<String>();
		List<String> linkList = new ArrayList<String>();

		String source = httpService.getSource(league.getLink());
		StringTokenizer line = new StringTokenizer(source, "|");

		while (line.hasMoreElements()) {
			String token = line.nextToken();

			if (token.startsWith("CO")) {
				order++;
			}

			if (token.startsWith("PA")) {
				switch (order) {
				case 1: // 경기시간
					dateList.add(token);
					break;
				case 2: // 팀명
					teamList.add(token);
					break;
				case 3: // 승무패 승 배당
					homeList.add(token);
					break;
				case 4: // 승무패 무 배당
					drawList.add(token);
					break;
				case 5: // 승무패 패 배당
					awayList.add(token);
					break;
				case 6: // 링크
					linkList.add(token);
					break;
				default:
					break;
				}
			}
		}

		for (int i = 0; i < dateList.size(); i++) {
			game = new Game();

			// 날짜
			game.setGameDate(convertDate(getTokenName(dateList.get(i), "NA")));
			// 팀명
			String[] teams = getTokenName(teamList.get(i), "NA").split(" v ");
			if (teams.length != 2) {
				throw new ConvertException(new Throwable("팀명 변환 에러"));
			}

			game.setHomeTeam(teams[0]);
			game.setAwayTeam(teams[1]);

			// 승무패
			Betting betting = new Betting();
			betting.setBettingScore("Goals");
			betting.setBettingType("1X2");
			betting.setBettingSet("Full Time");
			betting.setBettingCode("1X2");
			betting.setBettingName("Full Time Result");
			betting.setHandicap(0D);
			betting.setHandicapDescr("");
			betting.setHomeRate(convertRate(getTokenName(homeList.get(i), "NA")));
			betting.setDrawRate(convertRate(getTokenName(drawList.get(i), "NA")));
			betting.setAwayRate(convertRate(getTokenName(awayList.get(i), "NA")));
			betting.setHomeDescr(game.getHomeTeam());
			betting.setDrawDescr("Draw");
			betting.setAwayDescr(game.getAwayTeam());

			game.getBettingList().add(betting);
			game.setLink(convertLink(getTokenName(linkList.get(i), "PD")));

			// 나머지 베팅들
			this.getBettingList(game);

			// 게임설정 완료
			if (game.getBettingList().size() > 0) {
				league.getGameList().add(game);
			}
		}
	}

	@Override
	protected void getBettingList(Game game) {

		String source = httpService.getSource(game.getLink());
		StringTokenizer line = new StringTokenizer(source, "|");
		Map<String, String> map = new HashMap<String, String>();

		while (line.hasMoreElements()) {
			String token = line.nextToken();

			// Corners 링크
			if (token.startsWith("PA") && token.contains("NA=Corners")) {
				this.getCorner(game, convertLink(getTokenName(token, "PD")));
			}

			// Half 링크
			if (token.startsWith("PA") && token.contains("NA=Half")) {
				this.getHalf(game, convertLink(getTokenName(token, "PD")));
			}

			// Total Goals (Over/under)
			if (token.startsWith("MA") && token.contains("NA=Total Goals")) {
				map.put("link", convertLink(getTokenName(token, "PD")));
				map.put("bettingScore", "Goals");
				map.put("bettingType", "1-2");
				map.put("bettingSet", "Full Time");
				map.put("bettingCode", "Over/Under");
				map.put("bettingName", "Total Goals");
				getHandicap(game, map);
			}

			// Asian Handicap
			if (token.startsWith("MA") && token.contains("NA=Asian Handicap")) {
				map.put("link", convertLink(getTokenName(token, "PD")));
				map.put("bettingScore", "Goals");
				map.put("bettingType", "1-2");
				map.put("bettingSet", "Full Time");
				map.put("bettingCode", "Handicap");
				map.put("bettingName", "Asian Handicap");
				getHandicap(game, map);
			}

			// Goal Line
			if (token.startsWith("MA") && token.contains("NA=Goal Line")) {
				map.put("link", convertLink(getTokenName(token, "PD")));
				map.put("bettingScore", "Goals");
				map.put("bettingType", "1-2");
				map.put("bettingSet", "Full Time");
				map.put("bettingCode", "Over/Under");
				map.put("bettingName", "Goal Line");
				getHandicap(game, map);
			}

			// Alternative Asian Handicap
			if (token.contains("NA=Alternative Asian Handicap")) {
				map.put("link", convertLink(getTokenName(token, "PD")));
				map.put("bettingScore", "Goals");
				map.put("bettingType", "1-2");
				map.put("bettingSet", "Full Time");
				map.put("bettingCode", "Handicap");
				map.put("bettingName", "Alternative Asian Handicap");
				getHandicap(game, map);
			}

			// Alternative Goal Line
			if (token.startsWith("MA") && token.contains("NA=Alternative Goal Line")) {
				map.put("link", convertLink(getTokenName(token, "PD")));
				map.put("bettingScore", "Goals");
				map.put("bettingType", "1-2");
				map.put("bettingSet", "Full Time");
				map.put("bettingCode", "Over/Under");
				map.put("bettingName", "Alternative Goal Line");
				getHandicap(game, map);
			}

			// Draw No Bet
			if (token.startsWith("MA") && token.contains("NA=Draw No Bet")) {
				map.put("link", convertLink(getTokenName(token, "PD")));
				map.put("bettingScore", "Goals");
				map.put("bettingType", "1-2");
				map.put("bettingSet", "Full Time");
				map.put("bettingCode", "1-2");
				map.put("bettingName", "Draw No Bet");
				getHandicap(game, map);
			}

			// Handicap Result
			if (token.startsWith("MA") && token.contains("NA=Handicap Result")) {
				map.put("link", convertLink(getTokenName(token, "PD")));
				map.put("bettingScore", "Goals");
				map.put("bettingType", "1X2");
				map.put("bettingSet", "Full Time");
				map.put("bettingCode", "Handicap");
				map.put("bettingName", "Handicap Result");
				getMatch(game, map);
			}

			// Alternative Handicap Result
			if (token.startsWith("MA") && token.contains("NA=Alternative Handicap Result")) {
				map.put("link", convertLink(getTokenName(token, "PD")));
				map.put("bettingScore", "Goals");
				map.put("bettingType", "1X2");
				map.put("bettingSet", "Full Time");
				map.put("bettingCode", "Handicap");
				map.put("bettingName", "Alternative Handicap Result");
				getMatch(game, map);
			}
		}

	}

	/**
	 * 코너킥 정보를 가져온다.
	 * 
	 * @param game
	 * @param link
	 */
	private void getCorner(Game game, String link) {
		Map<String, String> map = new HashMap<String, String>();

		String source = httpService.getSource(link);
		StringTokenizer line = new StringTokenizer(source, "|");

		while (line.hasMoreElements()) {
			String token = line.nextToken();

			// Corners
			if (token.startsWith("MA") && token.contains("NA=Corners;")) {
				map.put("link", convertLink(getTokenName(token, "PD")));
				map.put("bettingScore", "Corners");
				map.put("bettingType", "1X2");
				map.put("bettingSet", "Full Time");
				map.put("bettingCode", "Handicap");
				map.put("bettingName", "Alternative Handicap Result");
				getMatch(game, map);
			}

			// Alternative Corners
			if (token.startsWith("MA") && token.contains("NA=Alternative Corners;")) {
				map.put("link", convertLink(getTokenName(token, "PD")));
				map.put("bettingScore", "Corners");
				map.put("bettingType", "1X2");
				map.put("bettingSet", "Full Time");
				map.put("bettingCode", "Over/Under");
				map.put("bettingName", "Alternative Corners");
				getMatch(game, map);
			}

			// Corners 2-Way
			if (token.startsWith("MA") && token.contains("NA=Corners 2-Way;")) {
				map.put("link", convertLink(getTokenName(token, "PD")));
				map.put("bettingScore", "Corners");
				map.put("bettingType", "1-2");
				map.put("bettingSet", "Full Time");
				map.put("bettingCode", "Over/Under");
				map.put("bettingName", "Corners 2-Way");
				getHandicap(game, map);
			}

			// First Half Corners
			if (token.startsWith("MA") && token.contains("NA=First Half Corners;")) {
				map.put("link", convertLink(getTokenName(token, "PD")));
				map.put("bettingScore", "Corners");
				map.put("bettingType", "1X2");
				map.put("bettingSet", "Half Time");
				map.put("bettingCode", "Over/Under");
				map.put("bettingName", "First Half Corners");
				getMatch(game, map);
			}

			// Corner Match Bet
			if (token.startsWith("MA") && token.contains("NA=Corner Match Bet;")) {
				map.put("link", convertLink(getTokenName(token, "PD")));
				map.put("bettingScore", "Corners");
				map.put("bettingType", "1X2");
				map.put("bettingSet", "Full Time");
				map.put("bettingCode", "Handicap");
				map.put("bettingName", "Corner Match Bet");
				getMatch(game, map);
			}

			// Corner Handicap
			if (token.startsWith("MA") && token.contains("NA=Corner Handicap;")) {
				map.put("link", convertLink(getTokenName(token, "PD")));
				map.put("bettingScore", "Corners");
				map.put("bettingType", "1X2");
				map.put("bettingSet", "Full Time");
				map.put("bettingCode", "Handicap");
				map.put("bettingName", "Corner Handicap");
				getMatch(game, map);
			}

			// Asian Handicap Corners
			if (token.startsWith("MA") && token.contains("NA=Asian Handicap Corners;")) {
				map.put("link", convertLink(getTokenName(token, "PD")));
				map.put("bettingScore", "Corners");
				map.put("bettingType", "1-2");
				map.put("bettingSet", "Full Time");
				map.put("bettingCode", "Handicap");
				map.put("bettingName", "Asian Handicap Corners");
				getHandicap(game, map);
			}

			// Asian Total Corners
			if (token.startsWith("MA") && token.contains("NA=Asian Total Corners;")) {
				map.put("link", convertLink(getTokenName(token, "PD")));
				map.put("bettingScore", "Corners");
				map.put("bettingType", "1-2");
				map.put("bettingSet", "Full Time");
				map.put("bettingCode", "Over/Under");
				map.put("bettingName", "Asian Total Corners");
				getHandicap(game, map);
			}

			// 1st Half Asian Corners
			if (token.startsWith("MA") && token.contains("NA=1st Half Asian Corners;")) {
				map.put("link", convertLink(getTokenName(token, "PD")));
				map.put("bettingScore", "Corners");
				map.put("bettingType", "1-2");
				map.put("bettingSet", "Half Time");
				map.put("bettingCode", "Over/Under");
				map.put("bettingName", "Asian Total Corners");
				getHandicap(game, map);
			}

		}
	}

	private void getHalf(Game game, String link) {
		Map<String, String> map = new HashMap<String, String>();

		String source = httpService.getSource(link);
		StringTokenizer line = new StringTokenizer(source, "|");

		while (line.hasMoreElements()) {
			String token = line.nextToken();

			// Half-Time
			if (token.startsWith("MA") && token.contains("NA=Half-Time;")) {
				map.put("link", convertLink(getTokenName(token, "PD")));
				map.put("bettingScore", "Goals");
				map.put("bettingType", "1X2");
				map.put("bettingSet", "Half Time");
				map.put("bettingCode", "Handicap");
				map.put("bettingName", "Half-Time");
				getMatch(game, map);
			}

			// 1st Half Asian Handicap
			if (token.startsWith("MA") && token.contains("NA=1st Half Asian Handicap;")) {
				map.put("link", convertLink(getTokenName(token, "PD")));
				map.put("bettingScore", "Goals");
				map.put("bettingType", "1X2");
				map.put("bettingSet", "Half Time");
				map.put("bettingCode", "Handicap");
				map.put("bettingName", "1st Half Asian Handicap");
				getMatch(game, map);
			}

			// Alternative 1st Half Asian Handicap
			if (token.startsWith("MA") && token.contains("NA=Alternative 1st Half Asian Handicap;")) {
				map.put("link", convertLink(getTokenName(token, "PD")));
				map.put("bettingScore", "Goals");
				map.put("bettingType", "1X2");
				map.put("bettingSet", "Half Time");
				map.put("bettingCode", "Handicap");
				map.put("bettingName", "Alternative 1st Half Asian Handicap");
				getMatch(game, map);
			}

		}

	}

}
